home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 1.toast / Sample Code / Human Interface Toolbox / Concordia / PopUpTkl.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-09-28  |  10.4 KB  |  257 lines  |  [TEXT/CWIE]

  1. /*
  2.     File:        PopUpTkl.c
  3.  
  4.     Contains:    the code to process the mPopUpMsg message from the Menu
  5.                 Manager.  This involves calculating the rectangle that the popup menu should
  6.                 appear in.
  7.  
  8.     Written by:     
  9.  
  10.     Copyright:    Copyright © 1999 by Apple Computer, Inc., All Rights Reserved.
  11.  
  12.                 You may incorporate this Apple sample source code into your program(s) without
  13.                 restriction. This Apple sample source code has been provided "AS IS" and the
  14.                 responsibility for its operation is yours. You are not permitted to redistribute
  15.                 this Apple sample source code as "Apple sample source code" after having made
  16.                 changes. If you're going to re-distribute the source, we require that you make
  17.                 it clear in the source that the code was descended from Apple sample source
  18.                 code, but that you've made changes.
  19.  
  20.     Change History (most recent first):
  21.                 8/10/1999    Karl Groethe    Updated for Metrowerks Codewarror Pro 2.1
  22.                 
  23.  
  24. */
  25.  
  26.  
  27. /******************************************************************************\
  28. * Header Files
  29. \******************************************************************************/
  30.  
  31. #include <Memory.h>
  32. #include <Menus.h>
  33. #include <OSUtils.h>
  34. #include <Script.h>
  35. #include <Types.h>
  36. #include "Concordia.h"
  37. #include "DrawTkl.h"
  38. #include "PopUpTkl.h"
  39. #include "SizeTkl.h"
  40.  
  41.  
  42. /******************************************************************************\
  43. * Prototypes
  44. \******************************************************************************/
  45.  
  46. void FindScreen (Rect *menuRect,
  47.                  Rect *retScreenRect);
  48.  
  49.  
  50. #pragma segment Main
  51. /******************************************************************************\
  52. * DoPopUpMsg - Calculate a popup menu's rectangle
  53. *
  54. * DoPopUpMsg calculates the menu rectangle for the popup menu specified by
  55. * TheMenu.  This rectangle is returned in MenuRect.  The top-left corner of the
  56. * menu item specified by PopUpItem will appear at the coordinates given by
  57. * TopPos and LeftPos.  The vertical coordinate of the top of the menu's
  58. * rectangle is returned.  If the menu runs off of the screen, its size and
  59. * position will be adjusted.
  60. *
  61. * Coding Notes
  62. * #A# - This loop calculates the total height of the menu (Height), the width of
  63. *       the menu (Width), the height of the tallest item in the menu
  64. *       (MaxHeight), and the distance from the top of the menu to the item
  65. *       specified by PopUpItem (ItemPos).
  66. * #B# - Read this as: if the height of this menu is too small to display the
  67. *       tallest menu item and two scroll icons,then. . .
  68. * #C# - If the height of the tallest menu item plus two scroll icons is more
  69. *       than the height of the entire menu, adjust the menu's position so that
  70. *       the entire menu is displayed.  Otherwise, set the height of the menu to
  71. *       the height of the tallest item plus two scroll icons.
  72. \******************************************************************************/
  73.  
  74. short
  75. DoPopUpMsg (MenuHandle TheMenu,Rect* MenuRect,short TopPos,short LeftPos,short PopUpItem)
  76. {
  77.     Str255      *ItemString; //-> Item's string
  78.     ItemInfoPtr ItemInfo;    //-> Item info
  79.     short       TestWidth;   //Width of item to test
  80.     short       TestHeight;  //Width of menu to test
  81.     short       Height;      //Height of menu
  82.     short       Width;       //Width of menu
  83.     short       MaxHeight;   //Height of tallest menu item
  84.     short       ItemInd;     //Item number of item being checked.
  85.     short       ItemPos;     //Dist from menu top to PopUpItem in pixels
  86.     short       MenuTop;     //Coord of top of menu rect, even if off screen
  87.     Rect        ScrnRect;    //Rectangle of screen minus menu bar and margins
  88.     short       HeightAdj;   //New coord of menu top/bottom if small menu
  89.  
  90.     Height = Width = MaxHeight = 0;
  91.     ItemInd = 1;
  92.     ItemPos = 0;
  93.     HLock ((Handle) TheMenu);
  94.     ItemString = (Str255 *) (**TheMenu).menuData;
  95.     ItemString = (Str255 *) ((Byte *) ItemString + strSize (*ItemString));
  96.     while ((*ItemString) [0] != (char) 0) //#A#
  97.         {
  98.         ItemInfo = (ItemInfoPtr) ((Byte *) *ItemString + strSize (*ItemString));
  99.         TestHeight = CalcItemHeight (*ItemString, ItemInfo);
  100.         TestWidth = CalcItemWidth (*ItemString, ItemInfo);
  101.         if (ItemInd == PopUpItem)
  102.             ItemPos = Height;
  103.         if (TestWidth > Width)
  104.             Width = TestWidth;
  105.         if (TestHeight > MaxHeight)
  106.             MaxHeight = TestHeight;
  107.         Height += TestHeight;
  108.         ItemInd += 1;
  109.         ItemString = (Str255 *) (ItemInfo + 1);
  110.         }
  111.     HUnlock ((Handle) TheMenu);
  112.     MenuTop = TopPos - ItemPos;
  113.     MenuRect->left = LeftPos;
  114.     MenuRect->top = MenuTop;
  115.     MenuRect->right = MenuRect->left + Width;
  116.     MenuRect->bottom = MenuRect->top + Height;
  117.     FindScreen (MenuRect, &ScrnRect);
  118.     InsetRect (&ScrnRect, scrnMargin, scrnMargin);
  119.     if (MenuRect->top < ScrnRect.top)
  120.         {
  121.         MenuRect->top = ScrnRect.top;
  122.         if (MenuRect->bottom - MenuRect->top - (short) (2 * scrlIconHeight) <
  123.                 MaxHeight) //#B#
  124.             {
  125.             if (MaxHeight + (short) (2 * scrlIconHeight) >= Height) //#C#
  126.                 HeightAdj = MenuRect->top + Height;
  127.             else
  128.                 HeightAdj = MenuRect->top + MaxHeight + (short) (2 *
  129.                         scrlIconHeight);
  130.             MenuTop += HeightAdj - MenuRect->bottom;
  131.             MenuRect->bottom = HeightAdj;
  132.             }
  133.         }
  134.     if (MenuRect->right > ScrnRect.right)
  135.         OffsetRect (MenuRect, ScrnRect.right - MenuRect->right, 0);
  136.     if (MenuRect->left < ScrnRect.left)
  137.         OffsetRect (MenuRect, ScrnRect.left - MenuRect->left, 0);
  138.     if (MenuRect->bottom > ScrnRect.bottom)
  139.         {
  140.         MenuRect->bottom = ScrnRect.bottom;
  141.         if (MenuRect->bottom - MenuRect->top - (short) (2 * scrlIconHeight) <
  142.                 MaxHeight) //#B#
  143.             {
  144.             if (MaxHeight + (short) (2 * scrlIconHeight) >= Height) //#C#
  145.                 HeightAdj = MenuRect->bottom - Height;
  146.             else
  147.                 HeightAdj = MenuRect->bottom - MaxHeight - (short) (2 *
  148.                         scrlIconHeight);
  149.             MenuTop -= MenuRect->top - HeightAdj;
  150.             MenuRect->top = HeightAdj;
  151.             }
  152.         }
  153.     return MenuTop;
  154.     }
  155.  
  156.  
  157. /******************************************************************************\
  158. * Private: FindScreen - Find rectangle of the screen containing most of the menu
  159. *
  160. * Color QuickDraw machines can have more than one screen, and pop-up menus
  161. * should appear on the screen that contains the most of the menu’s area.  This
  162. * function returns the rectangle of the screen (in global coordinates) that
  163. * contains most of the menu whose rectangle (also in global coordinates) is
  164. * passed in the menuRect parameter.  The screen’s rectangle is returned in the
  165. * retScreenRect parameter.  If the screen that contains the most of the menu is
  166. * the main screen (i.e. the screen with the menu bar), then the height of the
  167. * menu bar is added to the top of retScreenRect, effectively removing the menu
  168. * bar from the rectangle.  When Concordia is used on a machine without Color
  169. * QuickDraw, then the rectangle of the main screen is always returned.  Non-
  170. * Color QuickDraw machines with more than one screen (available from third-party
  171. * manufacturers) patch QuickDraw to support their screens, and it’s impossible
  172. * to determine the rectangles of the auxiliary screens without using
  173. * manufacturer-specific techniques.  Because of this, Concordia does not take
  174. * advantage of auxiliary screens on non-Color QuickDraw machines.
  175. *
  176. * The rectangles of all attached screens are determined through the GDevice list
  177. * that’s maintained by the system.  There’s one GDevice in the list for every
  178. * screen attached to the system.  GDevice routines only exist on Color QuickDraw
  179. * machines, so the first thing that FindScreen does is to determine whether it’s
  180. * running on a machine that has Color QuickDraw or not.  If it’s not, then the
  181. * screen rectangle is taken from the screenBits.bounds QuickDraw global.  If
  182. * Color QuickDraw is available, then the GDevice list is used to determine the
  183. * appropriate screen.
  184. *
  185. * The first GDevice in the GDevice list is retrieved from the GetDeviceList
  186. * function.  The next GDevice in the list is retrieved from the GetNextDevice
  187. * function.  Through these two functions, every GDevice in the GDevice list can
  188. * be retrieved.
  189. *
  190. * For every GDevice in the list, the area of intersection between the menu’s
  191. * rectangle and the screen’s rectangle (found in the gdRect field of the GDevice
  192. * structure) is calculated.  If the area of intersection is the greatest found
  193. * so far, then it and its GDevice is saved, and the rectangle of that screen is
  194. * placed into retScreenRect.
  195. *
  196. * After every GDevice in the GDevice list has been checked, the GDevice for the
  197. * screen containing most of the menu’s rectangle is checked to see if it’ the
  198. * GDevice for the main screen.  This is done by comparing the GDevice handle
  199. * against the handle for the main screen’s GDevice returned by GetMainDevice.
  200. * If the GDevice is in fact the main screen’s GDevice, then the height of the
  201. * menu bar is removed from retScreenRect.
  202. \******************************************************************************/
  203.  
  204. static void
  205. FindScreen (menuRect, retScreenRect)
  206.     Rect *menuRect;      /* Menu rectangle before processing for screen */
  207.     Rect *retScreenRect; /* Returns rectangle of screen appropriate for menu */
  208.     {
  209.     GDHandle  aGDevice;   /* Handle to each screen’s GDevice */
  210.     GDHandle  maxGDevice; /* Handle to GDevice containing most of menu */
  211.     long      area;       /* Menu rect/screen rect intersection area */
  212.     long      maxArea;    /* Max menu rect/screen rect intersect area found */
  213.     Rect      commonRect; /* Intersection between menu rect and screen rect */
  214.     SysEnvRec environs;   /* Current running environment */
  215.  
  216.     /* Determine whether Color QuickDraw is implemented or not */
  217.     (void) SysEnvirons (curSysEnvVers, /*<*/&environs);
  218.  
  219.     /* Use GDevices if Color QuickDraw is implemented, else use screenBits */
  220.     if (environs.hasColorQD)
  221.         {
  222.         /* Assume max intersection area is 0 and get first GDevice in list */
  223.         maxArea = 0L;
  224.         maxGDevice = nil;
  225.         aGDevice = GetDeviceList ();
  226.  
  227.         /* Loop through all screen GDevices */
  228.         while (aGDevice != nil)
  229.             {
  230.             /* Calc area of intersection between menu rect and screen rect */
  231.             SectRect (menuRect, &(**aGDevice).gdRect, /*<*/&commonRect);
  232.             area = (long) (commonRect.bottom - commonRect.top) * (commonRect.
  233.                     right - commonRect.left);
  234.  
  235.             /* If max area found so far, get screen’s rect and save area */
  236.             if (area > maxArea)
  237.                 {
  238.                 *retScreenRect = (**aGDevice).gdRect;
  239.                 maxGDevice = aGDevice;
  240.                 maxArea = area;
  241.                 }
  242.  
  243.             /* Go to the next GDevice in the list */
  244.             aGDevice = GetNextDevice (aGDevice);
  245.             }
  246.  
  247.         /* If GDevice with most of menu is main screen, remove MBar height */
  248.         if (maxGDevice == GetMainDevice ())
  249.             retScreenRect->top += GetMBarHeight ();
  250.         }
  251.     else
  252.         {
  253.         *retScreenRect = qd.screenBits.bounds;
  254.         retScreenRect->top += GetMBarHeight ();
  255.         }
  256.     }
  257.